package top.wuchu.rpc.transport.netty.server;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.wuchu.rpc.entity.RpcRequest;
import top.wuchu.rpc.entity.RpcResponse;
import top.wuchu.rpc.factory.SingletonFactory;
import top.wuchu.rpc.handler.RequestHandler;

/**
 * 自定义入栈处理器：Netty中处理RpcRequest的Handler
 * @author Wuchu
 */


public class NettyServerHandler extends SimpleChannelInboundHandler<RpcRequest> {

    private static final Logger logger = LoggerFactory.getLogger(NettyServerHandler.class);
    private final RequestHandler requestHandler;

    public NettyServerHandler() {
        this.requestHandler = SingletonFactory.getInstance(RequestHandler.class);
    }

    /**
     * 处理数据的地方
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcRequest msg) throws Exception {
        try {
            if(msg.getHeartBeat()) {
                logger.info("接收到客户端心跳包...");
                return;
            }
            logger.info("服务器接收到请求: {}", msg);

            /*
            * 调用 requestHandler.handle(msg) 处理该请求消息，并获取处理结果 result。
            * 检查当前通道是否是活跃的并且可写的。
            * 如果是，则通过 ctx.writeAndFlush() 将 RpcResponse.success(result, msg.getRequestId()) 发送回客户端
            */
            Object result = requestHandler.handle(msg);


            if (ctx.channel().isActive() && ctx.channel().isWritable()) {

                // 将响应结果发送给客户端
                ctx.writeAndFlush(RpcResponse.success(result, msg.getRequestId()));

                // 下面这种写法也可以
                //ctx.channel().writeAndFlush(RpcResponse.success(result, msg.getRequestId()));
            } else {
                logger.error("通道不可写");
            }
        } finally {
            ReferenceCountUtil.release(msg);
        }
    }

    /**
     * 处理上一个方法的异常信息
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("处理过程调用时有错误发生:");
        cause.printStackTrace();
        ctx.close();
    }

    /**
     * userEventTriggered是继承自ChannelInboundHandlerAdapter类中的一个方法，
     * 它主要用来处理当读写空闲时长超过设置的时间范围的回调
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.READER_IDLE) {
                logger.info("长时间未收到心跳包，断开连接...");
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

}
